package com.cqrt.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cqrt.config.ConfigurableFieldsConfig;
import com.cqrt.constant.RTErrorCodeEnum;
import com.cqrt.constant.RTPlmConstant;
import com.cqrt.constant.RTTableTypeConstant;
import com.cqrt.dto.TaskMessageDTO;
import com.cqrt.dto.TemplateDTO;

import com.cqrt.entity.RTPlanJobLinkDO;
import com.cqrt.entity.RTTemplateStatusDO;
import com.cqrt.mapper.PlanTemplateMappper;
import com.cqrt.mapper.RTProjectKnowledgeLinkMapper;
import com.cqrt.mapper.RTProjectsTemplateMapper;
import com.cqrt.mapper.RTTaskMapper;
import com.cqrt.service.RTProjectTemplateService;
import com.cqrt.util.TreeProcessor;
import com.cqrt.vo.ProjectManagerVO;
import com.hustcad.plm.basic.util.TyplmEntityBaseUtil;
import com.hustcad.plm.pdm.core.base.EntityBase;
import com.hustcad.plm.pdm.core.handle.exception.SystemErrorCodeEnum;
import com.hustcad.plm.pdm.enumeration.service.TyplmEnumerationService;
import com.hustcad.plm.pdm.redis.service.TyplmRedisService;
import com.hustcad.plm.pdm.redislock.TyplmRedisLockService;
import com.hustcad.plm.pdm.user.service.TyplmUserService;
import com.hustcad.plm.rpm.entityconvert.BaseConvert;
import com.hustcad.plm.rpm.general.service.container.GeneralOrgContainerService;
import com.hustcad.plm.rpm.model.dto.active.BatchLockParams;
import com.hustcad.plm.rpm.model.dto.active.ImportActiveDTO;
import com.hustcad.plm.rpm.model.dto.active.ImportChildActiveDTO;
import com.hustcad.plm.rpm.model.dto.active.PlusTaskDTO;
import com.hustcad.plm.rpm.model.dto.active.PlusTaskSaveDTO;
import com.hustcad.plm.rpm.model.dto.calendar.TyppmCalendarDTO;
import com.hustcad.plm.rpm.model.dto.folder.TyppmSubFolderDTO;
import com.hustcad.plm.rpm.model.dto.job.JobRemoteDTO;
import com.hustcad.plm.rpm.model.dto.job.JobTreeQueryDTO;
import com.hustcad.plm.rpm.model.dto.library.LibNodeTreeDTO;
import com.hustcad.plm.rpm.model.dto.message.ObjectMsgTempLinkDTO;
import com.hustcad.plm.rpm.model.dto.plan.PlanActiveLockDTO;
import com.hustcad.plm.rpm.model.dto.team.ProjectTeamTreeDTO;
import com.hustcad.plm.rpm.model.dto.team.TyppmTeamTreeDTO;
import com.hustcad.plm.rpm.model.entity.admin.TyppmProject;
import com.hustcad.plm.rpm.model.entity.admin.TyppmProjectTemplate;
import com.hustcad.plm.rpm.model.entity.folder.SubFolder;
import com.hustcad.plm.rpm.model.entity.library.TyppmProjectTemplateLib;
import com.hustcad.plm.rpm.model.entity.message.TyppmObjectSendMessageLink;
import com.hustcad.plm.rpm.model.entity.plan.TyppmPlan;
import com.hustcad.plm.rpm.model.vo.calendar.CalendarExceptionDayVO;
import com.hustcad.plm.rpm.model.vo.calendar.CalendarWeekDayVO;
import com.hustcad.plm.rpm.model.vo.job.TyppmJobVO;
import com.hustcad.plm.rpm.model.vo.message.ObjectMsgTempLinkVO;
import com.hustcad.plm.rpm.model.vo.project.ProjectTemplateVO;
import com.hustcad.plm.rpm.project.service.TyppmProjectService;
import com.hustcad.plm.rpm.service.calendar.TyppmCalendarService;
import com.hustcad.plm.rpm.service.folder.TyppmFolderMemberLinkService;
import com.hustcad.plm.rpm.service.folder.TyppmSubFolderService;
import com.hustcad.plm.rpm.service.importdata.TyppmImportDataService;
import com.hustcad.plm.rpm.service.job.TyppmJobService;
import com.hustcad.plm.rpm.service.library.TyppmProjectLibService;
import com.hustcad.plm.rpm.service.message.TyppmObjectSendMessageLinkService;
import com.hustcad.plm.rpm.service.plan.TyppmGanttChartService;
import com.hustcad.plm.rpm.service.plan.TyppmPlanActiveService;
import com.hustcad.plm.rpm.service.plan.TyppmPlanService;
import com.hustcad.plm.rpm.service.team.TyppmContainerTeamService;
import com.hustcad.plm.rpm.service.team.TyppmProjectTeamService;
import com.hustcad.plm.rpm.template.config.ProjectTemplateConfig;
import com.hustcad.plm.rpm.template.service.TyppmProjectTemplateLibService;
import com.hustcad.plm.rpm.template.service.TyppmProjectTemplateService;
import com.ty.basic.constant.TableTypeConstrant;
import com.ty.basic.entity.org.UserDO;
import com.ty.basic.response.ResponseResult;
import com.ty.basic.service.snow.SnowflakeIdComponent;
import com.ty.basic.session.TyAccountContext;
import com.ty.ppm.api.service.plan.GanttChartService;
import com.ty.ppm.api.service.projectlib.ProjectTemplateLibService;
import com.ty.ppm.model.utils.Tools;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static dm.jdbc.desc.Configuration.user;

@Slf4j
@Service
@Transactional
public class RTProjectTemplateServiceImpl implements RTProjectTemplateService {

    @Resource
    private TyppmSubFolderService typpmSubFolderService;
    @Resource
    private TyplmEnumerationService typlmEnumerationService;
    @Resource
    private TyppmProjectTemplateLibService typpmProjectTemplateLibService;
    @Resource
    private RTProjectsTemplateMapper rtProjectsTemplateMapper;
    @Resource
    private TyppmImportDataService typpmImportDataService;
    @Resource
    private TyppmCalendarService typpmCalendarService;
    @Resource
    private ConfigurableFieldsConfig configurableFieldsConfig;
    @Resource
    private SnowflakeIdComponent snowflakeIdComponent;
    @Resource
    private TyppmObjectSendMessageLinkService typpmObjectSendMessageLinkService;
    @Resource
    private TyppmPlanActiveService planActiveService;
    @Resource
    private TyppmProjectService typpmProjectService;
    @Resource
    private PlanTemplateMappper planTemplateMappper;
    @Resource
    private TyppmJobService typpmJobService;
    @Resource
    private BaseConvert baseConvert;
    @Resource
    private TyppmGanttChartService ganttChartService;
    @Resource
    private TyppmPlanService typpmPlanService;
    @Resource
    private TyppmContainerTeamService typpmContainerTeamService;
    @Resource
    private TyppmProjectTeamService typpmProjectTeamService;
    @Resource
    private TyplmUserService typlmUserService;
    @Resource
    private TyplmRedisService typlmRedisService;
    @Resource
    private TyplmRedisLockService typlmRedisLockService;
    @Resource
    private RTTaskMapper rtTaskMapper;


    @Override
    public Map<String, Map<String, String>> getAttr(List<String> enumDefs) {
        return typlmEnumerationService.getEnumItemsMap(enumDefs);
    }

    @Override
    public LibNodeTreeDTO getChildrenByParent(String key) {
        LibNodeTreeDTO libNodeTreeDTO = typpmProjectTemplateLibService.getLibSubFolderTree();
        Map<String, Map<String, String>> attrMap = getAttr(configurableFieldsConfig.getFields());
        List<String> keys = fuzzySearchKeys(attrMap, key);
        List<TyppmProjectTemplate> ProjectTemplatesList = rtProjectsTemplateMapper.queryProjectTemplateListByCondition(
                keys);
        List<String> templateIds = ProjectTemplatesList.stream()
                .map(TyppmProjectTemplate::getOid)
                .collect(Collectors.toList());
        if (templateIds.isEmpty()) {
            libNodeTreeDTO.setChildren(Collections.emptyList());
            return libNodeTreeDTO;
        }
        // 批量查询模板及其父文件夹信息
        List<TemplateDTO> templateDTOList = rtProjectsTemplateMapper.batchSelectTemplatesWithFolder(templateIds);
        Map<BigInteger, List<TemplateDTO>> templateGroupByFolder = templateDTOList.stream().collect(
                Collectors.groupingBy(TemplateDTO::getParentNodeOid));
        Map<String, LibNodeTreeDTO> nodeMap = new HashMap<>();
        flattenTreeToMap(libNodeTreeDTO, nodeMap);
        Set<String> foldersToKeep = new HashSet<>();
        for (BigInteger folderId : templateGroupByFolder.keySet()) {
            markPathToRoot(folderId, nodeMap, foldersToKeep);
        }
        LibNodeTreeDTO prunedTree = createPrunedTree(libNodeTreeDTO, foldersToKeep, nodeMap);

        for (Map.Entry<BigInteger, List<TemplateDTO>> entry : templateGroupByFolder.entrySet()) {
            BigInteger parentnodeoid = entry.getKey();
            List<TemplateDTO> templateDTOS = entry.getValue();
            LibNodeTreeDTO parentNode = findNodeInTree(prunedTree, parentnodeoid.toString());
            buildTemplateTree(parentNode, templateDTOS, parentnodeoid);
        }
        return prunedTree;
    }

    private void buildTemplateTree(LibNodeTreeDTO parentNode, List<TemplateDTO> templateDTOS,
                                   BigInteger parentnodeoid) {
        if (ObjectUtil.isNotNull(parentNode)) {
            for (TemplateDTO templateDTO : templateDTOS) {
                LibNodeTreeDTO libNode = new LibNodeTreeDTO();
                libNode.setName(templateDTO.getName());
                libNode.setOid(String.valueOf(templateDTO.getOid()));
                libNode.setOtype(templateDTO.getOtype());
                libNode.setParentFolderOID(String.valueOf(parentnodeoid));
                libNode.setParentFolderOTYPE(templateDTO.getFolderType());
                libNode.setPushMode(templateDTO.getPushMode());
                libNode.setDevelopmentLevel(templateDTO.getDevelopmentLevel());
                libNode.setDevelopmentMode(templateDTO.getDevelopmentMode());
                libNode.setProjectOID(templateDTO.getProjectOID());
                libNode.setProjectOTYPE(templateDTO.getProjectOTYPE());
                libNode.setProjectName(templateDTO.getProjectName());
                libNode.setCreatestamp(templateDTO.getCreatestamp());
                libNode.setUpdatestamp(templateDTO.getUpdatestamp());
                libNode.setModifystamp(templateDTO.getModifystamp());
                if (ObjectUtil.isNotEmpty(libNode.getProjectOID())) {
                    BigInteger planId = rtProjectsTemplateMapper.getPlanById(
                            Tools.toString(libNode.getProjectOID()));
                    libNode.setCurPlanOid(String.valueOf(planId));
                }
                if (rtProjectsTemplateMapper.existsTemplateStatus(Tools.toBigInteger(templateDTO.getOid())) == 1) {
                    libNode.setStatus("1");
                } else {
                    libNode.setStatus("0");
                }
                parentNode.getChildren().add(libNode);
            }
        }
    }

    private List<String> fuzzySearchKeys(Map<String, ?> searchMap, String searchTerm) {
        List<String> result = new ArrayList<>();
        if (CollectionUtil.isEmpty(searchMap) || StringUtils.isEmpty(searchTerm)) {
            return result;
        }
        for (Map.Entry<String, ?> entry : searchMap.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value instanceof String) {
                if (((String) value).contains(searchTerm)) {
                    result.add(key);
                }
            } else if (value instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, ?> nestedMap = (Map<String, ?>) value;
                List<String> nestedKeys = fuzzySearchKeys(nestedMap, searchTerm);
                result.addAll(nestedKeys);
            }
        }
        return result;
    }

    private void flattenTreeToMap(LibNodeTreeDTO node, Map<String, LibNodeTreeDTO> nodeMap) {
        if (ObjectUtil.isNull(node))
            return;
        nodeMap.put(node.getOid(), node);
        for (LibNodeTreeDTO child : node.getChildren()) {
            flattenTreeToMap(child, nodeMap);
        }
    }

    private void markPathToRoot(BigInteger folderId, Map<String, LibNodeTreeDTO> nodeMap, Set<String> foldersToKeep) {
        String currentId = folderId.toString();
        while (StringUtils.isNotEmpty(currentId)) {
            foldersToKeep.add(currentId);
            LibNodeTreeDTO currentNode = nodeMap.get(currentId);
            if (currentNode == null || currentNode.getParentFolderOID() == null) {
                break;
            }
            currentId = currentNode.getParentFolderOID();
        }
    }

    private LibNodeTreeDTO createPrunedTree(LibNodeTreeDTO originalRoot, Set<String> foldersToKeep,
                                            Map<String, LibNodeTreeDTO> nodeMap) {
        LibNodeTreeDTO newRoot = cloneNode(originalRoot);
        buildPrunedTree(newRoot, foldersToKeep, nodeMap);
        return newRoot;
    }

    private void buildPrunedTree(LibNodeTreeDTO newNode, Set<String> foldersToKeep,
                                 Map<String, LibNodeTreeDTO> nodeMap) {
        List<LibNodeTreeDTO> originalChildren = nodeMap.get(newNode.getOid()).getChildren();
        for (LibNodeTreeDTO originalChild : originalChildren) {
            if (foldersToKeep.contains(originalChild.getOid())) {
                LibNodeTreeDTO newChild = cloneNode(originalChild);
                newNode.getChildren().add(newChild);
                buildPrunedTree(newChild, foldersToKeep, nodeMap);
            }
        }
    }

    private LibNodeTreeDTO cloneNode(LibNodeTreeDTO original) {
        LibNodeTreeDTO clone = new LibNodeTreeDTO();
        clone.setOid(original.getOid());
        clone.setName(original.getName());
        clone.setOtype(original.getOtype());
        clone.setParentFolderOID(original.getParentFolderOID());
        clone.setParentFolderOTYPE(original.getParentFolderOTYPE());
        clone.setChildren(new ArrayList<>());
        return clone;
    }

    private LibNodeTreeDTO findNodeInTree(LibNodeTreeDTO root, String oid) {
        if (root.getOid().equals(oid)) {
            return root;
        }
        for (LibNodeTreeDTO child : root.getChildren()) {
            LibNodeTreeDTO found = findNodeInTree(child, oid);
            if (found != null) {
                return found;
            }
        }
        return null;
    }

    @Override
    public List<PlusTaskDTO> batchImportChildPlanActiveByPlanTemplatePlus(List<ImportChildActiveDTO> importActiveDTOs) {
        List<PlusTaskDTO> plusTaskDTOList = new ArrayList<>();
        String planActiveOid = importActiveDTOs.get(0).getPlanActiveOid();
        UserDO user = TyAccountContext.getUser();
        rtProjectsTemplateMapper.lockStatusById(Tools.toBigInteger(planActiveOid), user);
        for (ImportChildActiveDTO importActiveDTO : importActiveDTOs) {
            List<PlusTaskDTO> plusTaskDTOS = this.typpmImportDataService.importChildPlanActiveByPlanTemplatePlus(
                    importActiveDTO);
            if (CollectionUtil.isNotEmpty(plusTaskDTOS)) {
                plusTaskDTOList.addAll(plusTaskDTOS);
            }
        }

        rtProjectsTemplateMapper.unLockStatusById(Tools.toBigInteger(planActiveOid));

        List<RTPlanJobLinkDO> rtPlanJobLinkDOS=new ArrayList<>();
        for (PlusTaskDTO plusTaskDTO : plusTaskDTOList) {
            RTPlanJobLinkDO rtPlanJobLinkDO=new RTPlanJobLinkDO();
            String sourceActiveOid = plusTaskDTO.getSourceActiveOid();
            String id = plusTaskDTO.getId();
            rtPlanJobLinkDO.setPlanoid(new BigInteger(sourceActiveOid));
            rtPlanJobLinkDO.setJoboid(new BigInteger(id));
            rtPlanJobLinkDO.setOid(snowflakeIdComponent.getInstance().nextId());
            TyplmEntityBaseUtil.fillCommonFieldForCreate(rtPlanJobLinkDO);
            rtPlanJobLinkDOS.add(rtPlanJobLinkDO);
        }

        if (CollUtil.isNotEmpty(rtPlanJobLinkDOS)){
            rtProjectsTemplateMapper.batchInsertLink(rtPlanJobLinkDOS);
        }

        return plusTaskDTOList;
    }
    //批量导入一级任务
    @Override
    public List<PlusTaskDTO> batchImportPlansActiveByPlanTemplatePlus(List<ImportChildActiveDTO> importActiveDTOs) {

        List<PlusTaskDTO> plusTaskDTOList = new ArrayList<>();
        String planActiveOid = importActiveDTOs.get(0).getPlanActiveOid();
        String curPlanOid = importActiveDTOs.get(0).getCurPlanOid();
        String planTemplateOTYPE = importActiveDTOs.get(0).getPlanTemplateOTYPE();
        UserDO user = TyAccountContext.getUser();


            rtProjectsTemplateMapper.lockStatusById(Tools.toBigInteger(planActiveOid), user);
             if(planActiveOid!=null&&planActiveOid!=""&&
                curPlanOid!=null&&curPlanOid!=""&&
                planTemplateOTYPE!=null&&planTemplateOTYPE!="") {
            //批量导入一级任务
            for (ImportChildActiveDTO importChildActiveDTO : importActiveDTOs) {
                ImportActiveDTO importActiveDTO = new ImportActiveDTO();
                importChildActiveDTO.getPlanActiveOid();
                importActiveDTO.setPlanTemplateOTYPE(importChildActiveDTO.getPlanTemplateOTYPE());
                importActiveDTO.setPlanTemplateOID(importChildActiveDTO.getPlanTemplateOID());
                importActiveDTO.setCurPlanOID(importChildActiveDTO.getCurPlanOid());

                List<PlusTaskDTO> plusTaskDTOS = this.typpmImportDataService.importPlanActiveByPlanTemplatePlus(
                        importActiveDTO);
                if (CollectionUtil.isNotEmpty(plusTaskDTOS)) {
                    plusTaskDTOList.addAll(plusTaskDTOS);
                }
            }
        }
        rtProjectsTemplateMapper.unLockStatusById(Tools.toBigInteger(planActiveOid));

        List<RTPlanJobLinkDO> rtPlanJobLinkDOS=new ArrayList<>();
        for (PlusTaskDTO plusTaskDTO : plusTaskDTOList) {
            RTPlanJobLinkDO rtPlanJobLinkDO=new RTPlanJobLinkDO();
            String sourceActiveOid = plusTaskDTO.getSourceActiveOid();
            String id = plusTaskDTO.getId();
            plusTaskDTO.setParentOID(plusTaskDTO.getRootOID());
            rtPlanJobLinkDO.setPlanoid(new BigInteger(sourceActiveOid));
            rtPlanJobLinkDO.setJoboid(new BigInteger(id));
            rtPlanJobLinkDO.setOid(snowflakeIdComponent.getInstance().nextId());

            TyplmEntityBaseUtil.fillCommonFieldForCreate(rtPlanJobLinkDO);
            rtPlanJobLinkDOS.add(rtPlanJobLinkDO);
            if (plusTaskDTO.getSourceActiveOid()==null){

            }

        }

        if (CollUtil.isNotEmpty(rtPlanJobLinkDOS)){
            rtProjectsTemplateMapper.batchInsertLink(rtPlanJobLinkDOS);
//            planActiveService.unLockAllPlanActive(batchLockParams);
        }

        return plusTaskDTOList;
    }



    @Override
    public void batchUpdateCalendarExceptionDayList(List<String> projectList, String projectOid) {
        //判断选择的项目是否在执行中，是的话不给刷新
//        if (rtProjectsTemplateMapper.existExecuteProject(projectList) > 0) {
//            throw RTErrorCodeEnum.EXIST_EXECUTE_ERROR.getException("存在执行中项目，请重新选择");
//        }
        List<CalendarExceptionDayVO> TemplateExceptionVOList = typpmCalendarService.getCalendarExceptionDayByProjectOid(
                projectOid, TableTypeConstrant.TY_PROJECT_TYPE);
        List<BigInteger> CalendarIds = rtProjectsTemplateMapper.queryCalendarById(projectList);
        if (CollectionUtil.isNotEmpty(CalendarIds)) {
            for (BigInteger calendarId : CalendarIds) {
                List<CalendarExceptionDayVO> dayList = new ArrayList<>();
                if (CollectionUtil.isNotEmpty(TemplateExceptionVOList)) {
                    for (CalendarExceptionDayVO calendarExceptionDayVO : TemplateExceptionVOList) {
                        CalendarExceptionDayVO calendar = new CalendarExceptionDayVO();
                        BeanUtils.copyProperties(calendarExceptionDayVO, calendar,
                                                 "oid", "otype", "createstamp", "updatestamp", "modifystamp",
                                                 "updatecount",
                                                 "markForDelete");
                        calendar.setParentOid(calendarId.toString());
                        dayList.add(calendar);
                    }
                    typpmCalendarService.insertCalendarExceptionDayList(dayList);
                }
            }
        }
    }

    @Override
    public void updateTemplateStatus(String projectId, String statusKey) {
        String oid = rtProjectsTemplateMapper.selectTemplateById(projectId);
        String status = RTPlmConstant.statusMap.get(statusKey);
        RTTemplateStatusDO templateStatusDO = rtProjectsTemplateMapper.selectTemplateByOid(oid);
        if (ObjectUtil.isNotNull(templateStatusDO)) {
            if (StringUtils.equals(templateStatusDO.getStatus(), status)) {
                return;
            }
        }
        if (!StringUtils.equals(status, RTPlmConstant.TEMPLATE_STATE_EFFECTIVE)) {
            rtProjectsTemplateMapper.updateTemplateName(Tools.toBigInteger(oid), status);
            rtProjectsTemplateMapper.updateProjectsByTemplateId(Tools.toBigInteger(oid), status);
            rtProjectsTemplateMapper.updatePlansByTemplateId(Tools.toBigInteger(oid), status);
            String statu="";
            if(statusKey.equals("0")){
                statu="草稿";
                //rtProjectsTemplateMapper.updateTemplateStatus(Tools.toBigInteger(oid), statu);
            }else if(statusKey.equals("1")){
                statu="失效";
            }else if(statusKey.equals("2")){
                statu="生效";
            }



            if (ObjectUtil.isNull(templateStatusDO)) {
                RTTemplateStatusDO rtTemplateStatusDO = new RTTemplateStatusDO();
                rtTemplateStatusDO.setOid(snowflakeIdComponent.getInstance().nextId());
                rtTemplateStatusDO.setTemplateId(Tools.toBigInteger(oid));
                TyplmEntityBaseUtil.fillCommonFieldForCreate(rtTemplateStatusDO);
                rtTemplateStatusDO.setStatus(status);
                rtProjectsTemplateMapper.insertTemplate(rtTemplateStatusDO);
                log.info("===========模板状态=======>>>>,{}",status);
            } else {
                rtProjectsTemplateMapper.updateStatusById(Tools.toBigInteger(oid), status);
                log.info("=============模板状态=========>>>>,{}",status);
            }
        } else {
            rtProjectsTemplateMapper.restoreTemplateName(Tools.toBigInteger(oid),status);
            rtProjectsTemplateMapper.restoreProjectsByTemplateId(Tools.toBigInteger(oid),status);
            rtProjectsTemplateMapper.restorePlansByTemplateId(Tools.toBigInteger(oid),status);
            rtProjectsTemplateMapper.deleteStatusById(oid);
            log.info("==========模板状态========>>>>,{}",status);
        }
    }

    @Override
    public List<EntityBase> getChildrenByParentPlus(TemplateDTO templateDTO) {
        List<EntityBase> entities = typpmProjectTemplateLibService.getChildrenByParent(
                templateDTO.getParentOID(),
                templateDTO.getParentOTYPE(),
                templateDTO.getIsTemplate()
        );
        Map<String, Map<String, String>> attrMap = getAttr(configurableFieldsConfig.getFields());
        String pushModeKey = getKeyByValue(attrMap, templateDTO.getPushMode());
        String developmentLevelKey = getKeyByValue(attrMap, templateDTO.getDevelopmentLevel());
        Set<BigInteger> validTemplateIds = new HashSet<>(
                rtProjectsTemplateMapper.selectTemplateIdByCondition(pushModeKey, developmentLevelKey)
        );

        // 处理模板和子文件夹
        List<EntityBase> result = new ArrayList<>();
        Map<String, Map<String,String>> developmentMap = new HashMap<>();
        List<BigInteger> templateIdList = new ArrayList<>();

        for (EntityBase entity : entities) {
            if (entity instanceof SubFolder) {
                if(((SubFolder) entity).getName().contains("项目计划")) {
                    result.add(entity);
                }
            } else if (entity instanceof TyppmProjectTemplate) {
                TyppmProjectTemplate template = (TyppmProjectTemplate) entity;
                BigInteger oid = Tools.toBigInteger(template.getOid());
                if (validTemplateIds.contains(oid)) {
                    template.setPushMode(pushModeKey);
                    template.setDevelopmentLevel(developmentLevelKey);
                    templateIdList.add(oid);
                    result.add(template);
                }
            }
        }
        if (!templateIdList.isEmpty()) {
            developmentMap = rtProjectsTemplateMapper.batchSelectDevelopmentByOids(
                    templateIdList.stream().map(BigInteger::toString).collect(Collectors.toList())
            );

            Map<BigInteger, String> Map = new HashMap<>();

            for (Map<String, String> value : developmentMap.values()) {
                String developmentMode = value.get(RTPlmConstant.DEVELOPMENT_MODE);
                String oid = value.get("OID");
                Map.put(new BigInteger(oid),developmentMode);
            }
            // 设置开发模式
            for (EntityBase entity : result) {
                if (entity instanceof TyppmProjectTemplate) {
                    TyppmProjectTemplate template = (TyppmProjectTemplate) entity;
                    BigInteger oid = Tools.toBigInteger(template.getOid());
                    template.setDevelopmentMode(Map.get(oid));
                }
            }
        }
        return result;
    }

    @Override
    public List<TyppmCalendarDTO> batchUpdateCalendarDTOList(List<String> projectList, String projectOid) {
//        if (rtProjectsTemplateMapper.existExecuteProject(projectList) > 0) {
//            throw RTErrorCodeEnum.EXIST_EXECUTE_ERROR.getException("存在执行中项目，请重新选择");
//        }
        TyppmCalendarDTO templateCalendar = this.typpmCalendarService.getCalendarExceptionAndWeekDayByProjectOid(
                projectOid, TableTypeConstrant.TY_PROJECT_TYPE);
        Map<String, String> projectCalendarMap = new HashMap<>();
        for (String projectId : projectList) {
            BigInteger calendarId = rtProjectsTemplateMapper.selectCalendarById(projectId);
            if (calendarId != null) {
                projectCalendarMap.put(projectId, calendarId.toString());
            }
        }
        if (MapUtil.isEmpty(projectCalendarMap)) {
            return Collections.emptyList();
        }
        // 3. 批量查询所有日历的工作日
        List<String> calendarIdStrings = new ArrayList<>(projectCalendarMap.values());
        Map<String, List<CalendarWeekDayVO>> calendarWeekDaysMap = new HashMap<>();

        List<TyppmCalendarDTO> typpmCalendarDTOList = new ArrayList<>();

        if (!calendarIdStrings.isEmpty()) {
            List<CalendarWeekDayVO> weekDays = rtProjectsTemplateMapper.batchSelectWeekById(calendarIdStrings);
            calendarWeekDaysMap = weekDays.stream()
                    .collect(Collectors.groupingBy(CalendarWeekDayVO::getParentOid));
        }
        Map<Integer, CalendarWeekDayVO> templateWeekDayMap = templateCalendar.getWeekDays().stream()
                .collect(Collectors.toMap(CalendarWeekDayVO::getDayType, Function.identity()));
        // 4. 为每个项目创建日历DTO
        List<TyppmCalendarDTO> calendarDTOList = new ArrayList<>();
        Map<String, String> projectNameMap = new HashMap<>();
        if (!projectList.isEmpty()) {
            // 批量查询项目名称
            List<TyppmProject> projectNames = rtProjectsTemplateMapper.batchSelectNameById(projectList);
            projectNameMap = projectNames.stream()
                    .collect(Collectors.toMap(TyppmProject::getOid, TyppmProject::getName));
        }
        for (String projectId : projectList) {
            String calendarId = projectCalendarMap.get(projectId);
            if (calendarId == null) {
                continue;
            }
            // 创建新的日历对象
            TyppmCalendarDTO projectCalendar = new TyppmCalendarDTO();
            projectCalendar.setParentOID(projectId);
            projectCalendar.setParentOTYPE(TableTypeConstrant.TY_PROJECT_TYPE);
            projectCalendar.setOid(calendarId);
            projectCalendar.setOtype(TableTypeConstrant.TY_SYS_CALENDAR_OTYPE);
            projectCalendar.setName(projectNameMap.get(projectId));
            // 处理工作日
            List<CalendarWeekDayVO> weekDays = calendarWeekDaysMap.getOrDefault(calendarId, Collections.emptyList());
            for (CalendarWeekDayVO day : weekDays) {
                CalendarWeekDayVO templateDay = templateWeekDayMap.get(day.getDayType());
                if (templateDay != null) {
                    day.setDayWorking(templateDay.getDayWorking());
                }
                day.setParentOid(calendarId);
            }
            projectCalendar.setWeekDays(weekDays);
            List<CalendarExceptionDayVO> projectExceptions = new ArrayList<>();
            if (CollUtil.isNotEmpty(templateCalendar.getExceptions())) {
                for (CalendarExceptionDayVO ex : templateCalendar.getExceptions()) {
                    CalendarExceptionDayVO newEx = new CalendarExceptionDayVO();
                    BeanUtils.copyProperties(ex, newEx);
                    newEx.setParentOid(calendarId);
                    newEx.setOid(snowflakeIdComponent.getInstance().nextId().toString());// 设置新的parentOid
                    projectExceptions.add(newEx);
                }
            }
            projectCalendar.setExceptions(projectExceptions);
            List<TyppmCalendarDTO> calendarDTOS = typpmCalendarService.updateCalendarDTOList(
                    Collections.singletonList(projectCalendar));
            typpmCalendarDTOList.addAll(calendarDTOS);
        }
        if (!typpmCalendarDTOList.isEmpty()) {
            return typpmCalendarDTOList;
        }
        return Collections.emptyList();
    }

    @Override
    public void batchCreateObjectMessageLink(List<ObjectMsgTempLinkDTO> requestParams, String planOID) {
        JSONObject jsonObject = planActiveService.queryPlanActiveTreeByRootOIDAndRootOTYPE(planOID,
                                                                                           TableTypeConstrant.TY_PLAN_OTYPE,
                                                                                           Boolean.FALSE);
        Set<String> uIds = TreeProcessor.extractAllUIds(jsonObject);
        for (ObjectMsgTempLinkDTO requestParam : requestParams) {
            for (String uId : uIds) {
                ObjectMsgTempLinkDTO newObj = new ObjectMsgTempLinkDTO();
                BeanUtils.copyProperties(requestParam, newObj);
                newObj.setObjectOid(uId);
                newObj.setObjectOtype(TableTypeConstrant.TY_PLAN_ACTIVITY_OTYPE);
                typpmObjectSendMessageLinkService.createObjectMessageLink(newObj);
            }
        }
    }

    @Override
    public void batchUpdateMessageTemplateDefine(List<ObjectMsgTempLinkDTO> requestParams, String planOID) {
        JSONObject jsonObject = planActiveService.queryPlanActiveTreeByRootOIDAndRootOTYPE(planOID,
                                                                                           TableTypeConstrant.TY_PLAN_OTYPE,
                                                                                           Boolean.FALSE);
        Set<String> uIds = TreeProcessor.extractAllUIds(jsonObject);
        Map<String, Map<String, BigInteger>> templateToLinkOidMap = new HashMap<>();
        for (String uId : uIds) {
            for (ObjectMsgTempLinkDTO param : requestParams) {
                String templateOid = param.getTemplateOid();
                if (templateOid != null) {
                    BigInteger linkOid = rtProjectsTemplateMapper.getLinkOId(uId, templateOid);
                    if (linkOid != null) {
                        templateToLinkOidMap
                                .computeIfAbsent(templateOid, k -> new HashMap<>())
                                .put(uId, linkOid);
                    }
                }
            }
        }
        for (ObjectMsgTempLinkDTO param : requestParams) {
            String templateOid = param.getTemplateOid();
            Map<String, BigInteger> uIdToLinkOid = templateToLinkOidMap.getOrDefault(templateOid, Collections.emptyMap());
            for (Map.Entry<String, BigInteger> entry : uIdToLinkOid.entrySet()) {
                String uId = entry.getKey();
                BigInteger linkOid = entry.getValue();
                ObjectMsgTempLinkDTO newObj = new ObjectMsgTempLinkDTO();
                BeanUtils.copyProperties(param, newObj);
                newObj.setLinkOid(linkOid.toString());
                newObj.setObjectOid(uId);
                // 直接调用单条更新方法
                typpmObjectSendMessageLinkService.updateObjectMessageLink(newObj);
            }
        }
    }

    @Override
    public void batchDeleteObjectMessageLinkList(List<String> requestParams, String planOID) {
        JSONObject jsonObject = planActiveService.queryPlanActiveTreeByRootOIDAndRootOTYPE(planOID,
                                                                                           TableTypeConstrant.TY_PLAN_OTYPE,
                                                                                           Boolean.FALSE);
        Set<String> uIds = TreeProcessor.extractAllUIds(jsonObject);
        List<Map<String, String>> paramPairs = new ArrayList<>();
        for (String aoid : requestParams) {
            for (String boid : uIds) {
                Map<String, String> pair = new HashMap<>();
                pair.put("aoid", aoid);
                pair.put("boid", boid);
                paramPairs.add(pair);
            }
        }
        List<BigInteger> linkOIDS=rtProjectsTemplateMapper.batchSelectObjectMessageLinkList(paramPairs);
        List<String> linkOIDSAsString = linkOIDS.stream()
                .map(BigInteger::toString)
                .distinct()
                .collect(Collectors.toList());
        typpmObjectSendMessageLinkService.deleteObjectMessageLinkList(linkOIDSAsString);
    }

    @Override
    public void batchOperationObjectMessageLinkList(TaskMessageDTO taskMessageDTO) {
        if (ObjectUtil.isEmpty(taskMessageDTO.getRequestParam())) {
            return;
        }
        List<String> planOID = taskMessageDTO.getPlanOID();
        for (String uId : planOID) {
            ObjectMsgTempLinkDTO newObj = new ObjectMsgTempLinkDTO();
            BeanUtils.copyProperties(taskMessageDTO.getRequestParam(), newObj);
            newObj.setObjectOid(uId);
            newObj.setObjectOtype(TableTypeConstrant.TY_PLAN_ACTIVITY_OTYPE);
            typpmObjectSendMessageLinkService.createObjectMessageLink(newObj);
        }

    }

    @Override
    public List<EntityBase> getTemplateChildrenByParentPlus(TemplateDTO templateDTO) {
        return Collections.emptyList();
    }

    @Override
    public List<EntityBase> getPlanChildrenByParentPlus(TemplateDTO templateDTO) {
        String planName = rtProjectsTemplateMapper.selectPlanNameById(templateDTO.getPlanActiveOID());
        if (planName == null) {
            return Collections.emptyList();
        }

        List<EntityBase> entities = typpmProjectTemplateLibService.getChildrenByParent(
                templateDTO.getParentOID(),
                templateDTO.getParentOTYPE(),
                templateDTO.getIsTemplate()
        );
        if (entities.isEmpty()) {
            return Collections.emptyList();
        }

        Map<String, Map<String, String>> attrMap = getAttr(configurableFieldsConfig.getFields());
        String pushModeKey = getKeyByValue(attrMap, templateDTO.getPushMode());
        String developmentLevelKey = getKeyByValue(attrMap, templateDTO.getDevelopmentLevel());

        Set<BigInteger> validTemplateIds = new HashSet<>(
                rtProjectsTemplateMapper.selectTemplateIdByCondition(pushModeKey, developmentLevelKey)
        );
        if (validTemplateIds.isEmpty()) {
            return filterSubFolders(entities);
        }

        Map<String, Map<String, String>> templateToPlanMap = rtProjectsTemplateMapper.selectPlanOidByTemplateOids(
                new ArrayList<>(validTemplateIds)
        );
        if (templateToPlanMap.isEmpty()) {
            return filterSubFolders(entities);
        }

        Map<BigInteger, BigInteger> templatePlanMap = templateToPlanMap.values().stream()
                .map(map -> {
                    BigInteger templateOid = new BigInteger(map.get("templateOid"));
                    BigInteger planOid = new BigInteger(map.get("planOid"));
                    return new AbstractMap.SimpleEntry<>(templateOid, planOid);
                })
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        // 6. 筛选有效的计划OID
        List<BigInteger> validPlanOIDs = rtProjectsTemplateMapper.selectValidRootOids(
                new ArrayList<>(templatePlanMap.values()),
                planName
        );
        Set<BigInteger> validPlanOidSet = new HashSet<>(validPlanOIDs); // 转为Set提升查询效率

        Set<BigInteger> validTemplateOids = templatePlanMap.entrySet().stream()
                .filter(entry -> validPlanOidSet.contains(entry.getValue()))
                .map(Map.Entry::getKey)
                .collect(Collectors.toSet());

        List<EntityBase> result = new ArrayList<>();
        List<BigInteger> templateIdList = new ArrayList<>();

        for (EntityBase entity : entities) {
            if (entity instanceof SubFolder) {
                result.add(entity);
            } else if (entity instanceof TyppmProjectTemplate) {
                TyppmProjectTemplate template = (TyppmProjectTemplate) entity;
                BigInteger oid = Tools.toBigInteger(template.getOid());
                if (validTemplateOids.contains(oid)) {
                    template.setPushMode(pushModeKey);
                    template.setDevelopmentLevel(developmentLevelKey);
                    result.add(template);
                    templateIdList.add(oid);
                }
            }
        }

        if (!templateIdList.isEmpty()) {
            Map<String, Map<String, String>> developmentMap = rtProjectsTemplateMapper.batchSelectDevelopmentByOids(
                    templateIdList.stream().map(BigInteger::toString).collect(Collectors.toList())
            );

            Map<BigInteger, String> developmentModeMap = developmentMap.values().stream()
                    .map(map -> {
                        BigInteger oid = new BigInteger(map.get("OID"));
                        String mode = map.get(RTPlmConstant.DEVELOPMENT_MODE);
                        return new AbstractMap.SimpleEntry<>(oid, mode);
                    })
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

            // 为模板设置开发模式
            result.stream()
                    .filter(e -> e instanceof TyppmProjectTemplate)
                    .map(e -> (TyppmProjectTemplate) e)
                    .forEach(template -> {
                        BigInteger oid = Tools.toBigInteger(template.getOid());
                        template.setDevelopmentMode(developmentModeMap.get(oid));
                    });
        }

        return result;
    }

    @Override
    public LibNodeTreeDTO getAllChildrenByParentPlus(TemplateDTO templateDTO) {
        //1.获取整个文件夹树
        LibNodeTreeDTO libNodeTreeDTO = typpmProjectTemplateLibService.getLibSubFolderTree();
        LibNodeTreeDTO filterLibNodeTree = filterProjectPlanFolders(libNodeTreeDTO);
        List<TyppmProjectTemplate> ProjectTemplatesList = rtProjectsTemplateMapper.queryTemplateListByCondition(templateDTO);
        ProjectTemplatesList =ProjectTemplatesList
                .stream()
                .filter(f->{
                    String[] split = f.getName().split("-");
                    return split[split.length-1].equals("生效");
                }
        ).collect(Collectors.toList());
        List<String> templateIds = ProjectTemplatesList.stream()
                .map(TyppmProjectTemplate::getOid)
                .collect(Collectors.toList());
        if (templateIds.isEmpty()) {
            filterLibNodeTree.setChildren(Collections.emptyList());
            return filterLibNodeTree;
        }

        // 批量查询模板及其父文件夹信息
        List<TemplateDTO> templateDTOList = rtProjectsTemplateMapper.batchSelectTemplatesWithFolder(templateIds);
        Map<BigInteger, List<TemplateDTO>> templateGroupByFolder = templateDTOList.stream().collect(
                Collectors.groupingBy(TemplateDTO::getParentNodeOid));

        Map<String, LibNodeTreeDTO> nodeMap = new HashMap<>();
        flattenTreeToMap(filterLibNodeTree, nodeMap);
        Set<String> foldersToKeep = new HashSet<>();
        for (BigInteger folderId : templateGroupByFolder.keySet()) {
            markPathToRoot(folderId, nodeMap, foldersToKeep);
        }
        LibNodeTreeDTO prunedTree = createPrunedTree(filterLibNodeTree, foldersToKeep, nodeMap);

        for (Map.Entry<BigInteger, List<TemplateDTO>> entry : templateGroupByFolder.entrySet()) {
            BigInteger parentnodeoid = entry.getKey();
            List<TemplateDTO> templateDTOS = entry.getValue();
            LibNodeTreeDTO parentNode = findNodeInTree(prunedTree, parentnodeoid.toString());
            buildTemplateTree(parentNode, templateDTOS, parentnodeoid);
        }


        return prunedTree;
    }

    @Override
    public List<PlusTaskDTO> batchImportPlanActiveByPlanTemplatePlus(ImportActiveDTO importActiveDTO) {
        if (ObjectUtil.isNull(importActiveDTO) || CollUtil.isEmpty(
                importActiveDTO.getPlanTemplateOIDs()) || StringUtils.isEmpty(importActiveDTO.getPlanTemplateName())) {
            return Collections.emptyList();
        }
        List<String> templateNameList = splitPlanTemplateName(importActiveDTO.getPlanTemplateName());
        List<String> planTemplateOIDs=importActiveDTO.getPlanTemplateOIDs();
        List<PlusTaskDTO> plusTaskDTOS = new ArrayList<>();
        for (int i = 0; i < planTemplateOIDs.size(); i++) {
            importActiveDTO.setPlanTemplateOID(planTemplateOIDs.get(i));
            importActiveDTO.setPlanTemplateName(templateNameList.get(i));
            List<PlusTaskDTO> plusTaskDTOList = typpmImportDataService.importPlanActiveByPlanTemplatePlus(importActiveDTO);
            if (CollUtil.isNotEmpty(plusTaskDTOList)){
                plusTaskDTOS.addAll(plusTaskDTOList);
            }
        }

        List<RTPlanJobLinkDO> rtPlanJobLinkDOS=new ArrayList<>();
        for (PlusTaskDTO plusTaskDTO : plusTaskDTOS) {
            RTPlanJobLinkDO rtPlanJobLinkDO=new RTPlanJobLinkDO();
            String sourceActiveOid = plusTaskDTO.getSourceActiveOid();
            String id = plusTaskDTO.getId();
            rtPlanJobLinkDO.setPlanoid(new BigInteger(sourceActiveOid));
            rtPlanJobLinkDO.setJoboid(new BigInteger(id));
            rtPlanJobLinkDO.setOid(snowflakeIdComponent.getInstance().nextId());
            TyplmEntityBaseUtil.fillCommonFieldForCreate(rtPlanJobLinkDO);
            rtPlanJobLinkDOS.add(rtPlanJobLinkDO);
        }

        if (CollUtil.isNotEmpty(rtPlanJobLinkDOS)){
            rtProjectsTemplateMapper.batchInsertLink(rtPlanJobLinkDOS);
        }


        return plusTaskDTOS;
    }

//    @Override
//    public ProjectTemplateVO selectTemplateValueByOId(String templateOid) {
//        BigInteger bigInteger = rtProjectsTemplateMapper.selectTemplateValueByOId(templateOid);
//        return null;
//    }


    private List<String> splitPlanTemplateName(String name) {
        return Arrays.stream(name.split(","))
                .filter(part -> !part.isEmpty()) // 过滤空字符串
                .collect(Collectors.toList());
    }

    public LibNodeTreeDTO filterProjectPlanFolders(LibNodeTreeDTO root) {
        if (root == null) {
            return null;
        }
        // 1. 深拷贝当前节点（不包含子节点）
        LibNodeTreeDTO filteredNode = copyNodeWithoutChildren(root);
        // 2. 递归处理子节点
        List<LibNodeTreeDTO> filteredChildren = new ArrayList<>();
        for (LibNodeTreeDTO child : root.getChildren()) {
            LibNodeTreeDTO filteredChild = filterProjectPlanFolders(child);
            if (filteredChild != null) {
                filteredChildren.add(filteredChild);
            }
        }
        // 3. 设置过滤后的子节点
        filteredNode.setChildren(filteredChildren);
        boolean hasMatchingName = root.getName() != null &&
                root.getName().contains("项目计划");
        boolean hasValidChildren = !filteredChildren.isEmpty();
        return (hasMatchingName || hasValidChildren) ? filteredNode : null;
    }

    private LibNodeTreeDTO copyNodeWithoutChildren(LibNodeTreeDTO source) {
        LibNodeTreeDTO copy = new LibNodeTreeDTO();
        copy.setOid(source.getOid());
        copy.setOtype(source.getOtype());
        copy.setName(source.getName());
        copy.setParentFolderOID(source.getParentFolderOID());
        copy.setParentFolderOTYPE(source.getParentFolderOTYPE());
        copy.setUpdatecount(source.getUpdatecount());
        copy.setMarkForDelete(source.getMarkForDelete());
        copy.setCreatestamp(source.getCreatestamp());
        copy.setUpdatestamp(source.getUpdatestamp());
        copy.setModifystamp(source.getModifystamp());
        return copy;
    }


    private List<EntityBase> filterSubFolders(List<EntityBase> entities) {
        return entities.stream()
                .filter(e -> e instanceof SubFolder)
                .collect(Collectors.toList());
    }


    public String getKeyByValue(Map<String, Map<String, String>> attrMap, String value) {
        if (attrMap == null || value == null) {
            return null;
        }
        // 遍历所有一级映射（如developmentLevel、pushMode）
        for (Map<String, String> innerMap : attrMap.values()) {
            // 遍历二级映射的键值对，寻找匹配的值
            for (Map.Entry<String, String> entry : innerMap.entrySet()) {
                if (value.equals(entry.getValue())) {
                    return entry.getKey(); // 找到第一个匹配的key就返回
                }
            }
        }
        return null;
    }


    public JSONObject querySimilarTemplate(String oid){
        List<String> similarTemplateOidList = planTemplateMappper.selectSimilarTemplate(oid);
        if(CollUtil.isNotEmpty(similarTemplateOidList)){
            TyppmProjectTemplateLib lib = this.typpmProjectTemplateLibService.getDefaultProjectTemplateLib();
            JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(lib));
            jsonObject.put("child",new ArrayList<>());
            dealTemplate(lib.getOid(),lib.getOtype(),jsonObject,similarTemplateOidList);
            return jsonObject;
        }else {
            throw RTErrorCodeEnum.REMOTEOBJ_NOT_EXIST.getException("没有可选择的模板模板");
        }
    }

    private void dealTemplate(String oid, String otype,JSONObject parent,List<String> similarTemplateOidList) {
        List<EntityBase> list = this.typpmProjectTemplateLibService.getChildrenByParent(oid, otype, 2);
        if(CollUtil.isNotEmpty(list)){
            for (EntityBase entityBase : list) {
                String type = entityBase.getOtype();
                JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(entityBase));
                json.put("child",new ArrayList<>());
                if(type.equals(TableTypeConstrant.TY_PJ_PROJECTTEMPLATE_OTYPE)){
                    if(similarTemplateOidList.contains(entityBase.getOid())){
                        JSONArray child = parent.getJSONArray("child");
                        child.add(json);
                    }
                }else {
                    JSONArray child = parent.getJSONArray("child");
                    child.add(json);
                    dealTemplate(entityBase.getOid(),type,json,similarTemplateOidList);
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchReplaceProjectManger(JSONObject params) {
        UserDO user = TyAccountContext.getUser();
        String key = "batchReplaceProjectManger" + "@@" + user.getOid();
        String lock = typlmRedisService.getString(key);
        if (!StringUtils.isEmpty(lock)) {
            return;
        }
        typlmRedisLockService.lock(key);
        try {
            JSONArray projectList = params.getJSONArray("projectList");
            String oldManagerOid = params.getString("oldManagerOid");
            String newManagerOid = params.getString("newManagerOid");
            List<String> errors = new ArrayList<>();
            for (int i = 0; i < projectList.size(); i++) {
                JSONObject project = projectList.getJSONObject(i);
                dealProjectManger(project, oldManagerOid, errors, newManagerOid);
            }
            if (CollUtil.isNotEmpty(errors)) {
                throw RTErrorCodeEnum.UPDATA_PROJECT_MANAGER_ERROR.getException(errors);
            }
        } finally {
            typlmRedisLockService.unlock(key);
        }
    }


    @Override
    public List<ProjectManagerVO> selectProjectByManger(JSONObject params) {
        String manger = params.getString("manger");
        String projectName = params.getString("projectName");
        String projectNumber = params.getString("projectNumber");

        List<String> nameList =null;
        List<String> numberList=null;
        if(StrUtil.isNotBlank(projectName)){
            nameList = new ArrayList<>(Arrays.asList(projectName.split(" ")));
        }
        if(StrUtil.isNotBlank(projectNumber)){
            numberList = new ArrayList<>(Arrays.asList(projectNumber.split(" ")));
        }
        List<ProjectManagerVO> data = rtProjectsTemplateMapper.queryProjectByManger(manger,nameList,numberList);
        data.removeIf(object -> object != null && (object.getProjectNumber() == null || object.getProjectNumber().startsWith("DEL")||object.getIsTemplate().equals("2")));
        return data;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteProjectManger(JSONObject params) {
        JSONArray projectList = params.getJSONArray("projectList");
        String managerOid = params.getString("managerOid");
        List<String> errors = new ArrayList<>();
        for (int i = 0; i < projectList.size(); i++) {
            JSONObject project = projectList.getJSONObject(i);
            dealProjectManger(project, managerOid, errors,null);
        }
        if(CollUtil.isNotEmpty(errors)){
            throw RTErrorCodeEnum.UPDATA_PROJECT_MANAGER_ERROR.getException(errors);
        }
    }

    private void dealProjectManger(JSONObject project, String managerOid, List<String> errors, String newManagerOid) {
        String projectOid = project.getString("projectId");
        Map<String, Object> pmMap = new HashMap<>();
        pmMap.put("projectOid", projectOid);
        pmMap.put("userOid", managerOid);
        pmMap.put("roleName", "PROJECT MANAGER");
        String name = project.getString("projectName");
        try {
            this.typpmProjectService.deleteProjectManagerOrAdministrator(pmMap);
            if (StringUtils.isNotBlank(newManagerOid)) {
                pmMap.put("userOid", newManagerOid);
                this.typpmProjectService.doInsertProjectManagerOrAdministrator(pmMap);
            }
        } catch (Exception e) {
            String message = e.getMessage();
            String errorMessage = "项目[" + name + "]处理异常:" + message;
            errors.add(errorMessage);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchReplaceJobExecutor(JSONObject params) {
        UserDO user = TyAccountContext.getUser();
        String key = "batchReplaceJobExecutor" + "@@" + user.getOid();
        String lock = typlmRedisService.getString(key);
        if (!StringUtils.isEmpty(lock)) {
            return;
        }
        typlmRedisLockService.lock(key);
        try {
            String oldExecutorId = params.getString("oldExecutorId");
            String newExecutorId = params.getString("newExecutorId");
            boolean isProject = params.getBoolean("isProject");
            JSONArray projectList = params.getJSONArray("projectId");
            for (int i = 0; i < projectList.size(); i++) {
                String projectId = projectList.getString(i);

                if(isProject){
                    // 如果是项目 须转交任务替换任务执行人
                    JobTreeQueryDTO queryDTO = new JobTreeQueryDTO();
                    queryDTO.setProjectOid(projectId);
                    List<TyppmJobVO> result = this.typpmJobService.getJobTreeByParams(queryDTO);
                    List<TyppmJobVO> needReplaceJobList = new ArrayList<>();
                    getNeedReplaceJobList(result, oldExecutorId, needReplaceJobList);
                    if(CollUtil.isNotEmpty(needReplaceJobList)){
                        for (TyppmJobVO job : needReplaceJobList) {
                            JobRemoteDTO jobRemoteDTO = this.baseConvert.copyProperties(job, JobRemoteDTO.class);
                            jobRemoteDTO.setTypeoid(Tools.toBigInteger(job.getTypeOID()));
                            jobRemoteDTO.setTypeotype(job.getTypeOTYPE());
                            jobRemoteDTO.setExecutorOID(Tools.toBigInteger(newExecutorId));
                            this.typpmJobService.updateJobAndCalculate(jobRemoteDTO);
                        }
                    }
                }

                //替换计划执行人
                TyppmPlan plan = this.typpmPlanService.queryPlanDTOByParent(projectId, TableTypeConstrant.TY_PROJECT_TYPE);
                JSONObject projectTree = planActiveService.queryPlanActiveTreeByRootOIDAndRootOTYPE(plan.getOid(), TableTypeConstrant.TY_PLAN_OTYPE, Boolean.FALSE);
                List<PlusTaskSaveDTO> plusTaskSaveDTOS = extractTasksWithExecutor(projectTree, oldExecutorId, newExecutorId);
                for (PlusTaskSaveDTO plusTaskSaveDTO : plusTaskSaveDTOS) {
                    plusTaskSaveDTO.setLineNumber(plusTaskSaveDTO.getOutLineLevel());
                    plusTaskSaveDTO.setEarlyStart(formatDateTime(plusTaskSaveDTO.getEarlyStart()));
                    plusTaskSaveDTO.setEarlyFinish(formatDateTime(plusTaskSaveDTO.getEarlyFinish()));
                    plusTaskSaveDTO.setLateFinish(formatDateTime(plusTaskSaveDTO.getLateFinish()));
                    plusTaskSaveDTO.setLateStart(formatDateTime(plusTaskSaveDTO.getLateStart()));
                    plusTaskSaveDTO.setStartDate(formatDateTime(plusTaskSaveDTO.getStartDate()));
                    plusTaskSaveDTO.setFinishDate(formatDateTime(plusTaskSaveDTO.getFinishDate()));
                    plusTaskSaveDTO.setConstraintDate(formatDateTime(plusTaskSaveDTO.getConstraintDate()));
                    plusTaskSaveDTO.setActualFinishDate(formatDateTime(plusTaskSaveDTO.getActualFinishDate()));
                    plusTaskSaveDTO.setActualStartDate(formatDateTime(plusTaskSaveDTO.getActualStartDate()));
                    plusTaskSaveDTO.setActualStartDate(formatDateTime(plusTaskSaveDTO.getActualStartDate()));
                }
                this.ganttChartService.saveTableTreeEx(plan.getOid(), plusTaskSaveDTOS);
                UserDO newExecutorDO = typlmUserService.queryUserByKey(new BigInteger(newExecutorId));

                // 替换成员
                List<ProjectTeamTreeDTO> teamList = this.typpmProjectTeamService.queryContainerTeamByContainer(projectId, TableTypeConstrant.TY_PROJECT_TYPE);
                for (ProjectTeamTreeDTO projectTeamTreeDTO : teamList) {
                    String tag = projectTeamTreeDTO.getTag();
                    if(tag.contains("模块") || tag.contains("组长")){
                        List<TyppmTeamTreeDTO> children = projectTeamTreeDTO.getChildren();
                        Map<String, TyppmTeamTreeDTO> userMap = children.stream()
                                .collect(Collectors.toMap(TyppmTeamTreeDTO::getOid, Function.identity()));
                        if(CollUtil.isNotEmpty(userMap) && userMap.containsKey(oldExecutorId)){
                            //删除旧的
                            TyppmTeamTreeDTO deleteTeamTreeDTO = userMap.get(oldExecutorId);
                            deleteTeamTreeDTO.setProjectOID(projectId);
                            deleteTeamTreeDTO.setProjectOTYPE(TableTypeConstrant.TY_PROJECT_TYPE);
                            deleteTeamTreeDTO.setGroupName(projectTeamTreeDTO.getName());
                            deleteTeamTreeDTO.setOtype(TableTypeConstrant.TY_USER_OTYPE);
                            this.typpmContainerTeamService.deleteTeamItemByContainer("", "", deleteTeamTreeDTO);
                            //增加新的
                            TyppmTeamTreeDTO addTeamTreeDTO = new TyppmTeamTreeDTO();
                            addTeamTreeDTO.setOid(newExecutorId);
                            addTeamTreeDTO.setOtype(TableTypeConstrant.TY_USER_OTYPE);
                            addTeamTreeDTO.setProjectOID(projectId);
                            addTeamTreeDTO.setProjectOTYPE(TableTypeConstrant.TY_PROJECT_TYPE);
                            addTeamTreeDTO.setFullName(newExecutorDO.getDisplayName());
                            addTeamTreeDTO.setFullNamePinyin(newExecutorDO.getName());
                            addTeamTreeDTO.setUserFullName(newExecutorDO.getDisplayName());
                            addTeamTreeDTO.setName(newExecutorDO.getName());
                            projectTeamTreeDTO.setChildren(Collections.singletonList(addTeamTreeDTO));
                            this.typpmProjectTeamService.insertRoleAndUserByContainerJAC(projectId, TableTypeConstrant.TY_PROJECT_TYPE, projectTeamTreeDTO);
                        }
                    }
                }
            }
        } finally {
            typlmRedisLockService.unlock(key);
        }
    }


    @Transactional(rollbackFor = Exception.class)
    public void batchReplaceJobExecutorEX(JSONObject params) {
        UserDO user = TyAccountContext.getUser();
        String key = "batchReplaceJobExecutor" + "@@" + user.getOid();
        String lock = typlmRedisService.getString(key);
        if (!StringUtils.isEmpty(lock)) {
            return;
        }
        typlmRedisLockService.lock(key);
        try {
            String oldExecutorId = params.getString("oldExecutorId");
            String newExecutorId = params.getString("newExecutorId");
            JSONArray jobList = params.getJSONArray("jobId");
            String projectId = params.getString("projectId");
            String tags= params.getString("tags");
            //替换计划执行人
            TyppmPlan plan = this.typpmPlanService.queryPlanDTOByParent(projectId, TableTypeConstrant.TY_PROJECT_TYPE);
            JSONObject projectTree = planActiveService.queryPlanActiveTreeByRootOIDAndRootOTYPE(plan.getOid(), TableTypeConstrant.TY_PLAN_OTYPE, Boolean.FALSE);
            List<PlusTaskSaveDTO> plusTaskSaveDTOS = extractTasksWithExecutor(projectTree, oldExecutorId, newExecutorId);
            for (PlusTaskSaveDTO plusTaskSaveDTO : plusTaskSaveDTOS) {
                plusTaskSaveDTO.setLineNumber(plusTaskSaveDTO.getOutLineLevel());
                plusTaskSaveDTO.setEarlyStart(formatDateTime(plusTaskSaveDTO.getEarlyStart()));
                plusTaskSaveDTO.setEarlyFinish(formatDateTime(plusTaskSaveDTO.getEarlyFinish()));
                plusTaskSaveDTO.setLateFinish(formatDateTime(plusTaskSaveDTO.getLateFinish()));
                plusTaskSaveDTO.setLateStart(formatDateTime(plusTaskSaveDTO.getLateStart()));
                plusTaskSaveDTO.setStartDate(formatDateTime(plusTaskSaveDTO.getStartDate()));
                plusTaskSaveDTO.setFinishDate(formatDateTime(plusTaskSaveDTO.getFinishDate()));
                plusTaskSaveDTO.setConstraintDate(formatDateTime(plusTaskSaveDTO.getConstraintDate()));
                plusTaskSaveDTO.setActualFinishDate(formatDateTime(plusTaskSaveDTO.getActualFinishDate()));
                plusTaskSaveDTO.setActualStartDate(formatDateTime(plusTaskSaveDTO.getActualStartDate()));
                plusTaskSaveDTO.setActualStartDate(formatDateTime(plusTaskSaveDTO.getActualStartDate()));
            }
          //  this.ganttChartService.saveTableTreeEx(plan.getOid(), plusTaskSaveDTOS);
            UserDO newExecutorDO = typlmUserService.queryUserByKey(new BigInteger(newExecutorId));
            // 替换成员
            List<ProjectTeamTreeDTO> teamList = this.typpmProjectTeamService.queryContainerTeamByContainer(projectId, TableTypeConstrant.TY_PROJECT_TYPE);
            for (ProjectTeamTreeDTO projectTeamTreeDTO : teamList) {
                String tag = projectTeamTreeDTO.getTag();
                if(tag.contains("代表") || tag.contains("者")||tag.contains("人")){
                    List<TyppmTeamTreeDTO> children = projectTeamTreeDTO.getChildren();
                    Map<String, TyppmTeamTreeDTO> userMap = children.stream()
                            .collect(Collectors.toMap(TyppmTeamTreeDTO::getOid, Function.identity()));
                    if(CollUtil.isNotEmpty(userMap) && userMap.containsKey(oldExecutorId)){
                        boolean isExist = false;
                        for (TyppmTeamTreeDTO typpmTeamTreeDTO:children){
                            if (typpmTeamTreeDTO.getOid().equals(newExecutorId)) {
                                isExist = true;
                            }
                        }
                        if(!isExist&&tag.equals(tags)) {
                            //增加新的
                            TyppmTeamTreeDTO addTeamTreeDTO = new TyppmTeamTreeDTO();
                            addTeamTreeDTO.setOid(newExecutorId);
                            addTeamTreeDTO.setOtype(TableTypeConstrant.TY_USER_OTYPE);
                            addTeamTreeDTO.setProjectOID(projectId);
                            addTeamTreeDTO.setProjectOTYPE(TableTypeConstrant.TY_PROJECT_TYPE);
                            addTeamTreeDTO.setFullName(newExecutorDO.getDisplayName());
                            addTeamTreeDTO.setFullNamePinyin(newExecutorDO.getName());
                            addTeamTreeDTO.setUserFullName(newExecutorDO.getDisplayName());
                            addTeamTreeDTO.setName(newExecutorDO.getName());
                            projectTeamTreeDTO.setChildren(Collections.singletonList(addTeamTreeDTO));
                            this.typpmProjectTeamService.insertRoleAndUserByContainerJAC(projectId,
                                                                                         TableTypeConstrant.TY_PROJECT_TYPE,
                                                                                         projectTeamTreeDTO);
                        }
                    }
                }
            }
            for (int i = 0; i < jobList.size(); i++) {
                String jobId = jobList.getString(i);
                rtTaskMapper.updateExcutorByJobId(jobId, newExecutorId);
                BigInteger bigInteger = rtTaskMapper.selectActivityIdById(jobId);
                if (bigInteger != null){
                    rtTaskMapper.updateExecutorByActivityId(bigInteger, newExecutorId);
                    //rtTaskMapper.updateWorkByActivityId(bigInteger, tags);
                }
            }
        } finally {
            typlmRedisLockService.unlock(key);
        }
    }
    @Override
    public List<ProjectManagerVO> selectProjectByMember(String member, String projectName, String projectNumber,String thisYear) {
        return rtProjectsTemplateMapper.selectProjectByMember(member,projectName,projectNumber,thisYear);
    }



    private static String formatDateTime(String dateTimeStr) {
        if (StringUtils.isEmpty(dateTimeStr)) {
            return dateTimeStr;
        }
        return dateTimeStr.replace("T", " ").replaceAll("\\.\\d+", "");
    }

    private List<PlusTaskSaveDTO> extractTasksWithExecutor(JSONObject projectTree, String oldExecutorId, String newExecutorId) {
        List<PlusTaskSaveDTO> plusTaskSaveDTOS = new ArrayList<>();

        JSONArray taskArray = projectTree.getJSONArray("Tasks");
        if (CollUtil.isNotEmpty(taskArray)) {
            for (int i = 0; i < taskArray.size(); i++) {
                JSONObject task = taskArray.getJSONObject(i);
                // 处理当前任务
                dealCurrentPlanExecutor(task, oldExecutorId, newExecutorId, plusTaskSaveDTOS);
                // 处理子任务
                processChildrenTasks(task, oldExecutorId, newExecutorId, plusTaskSaveDTOS);
            }
        }
        return plusTaskSaveDTOS;
    }

    /**
     * 处理任务及其子任务
     * @param task 父任务
     * @param oldExecutorId 原执行人ID
     * @param newExecutorId 新执行人ID
     * @param result 结果列表
     */
    private void processChildrenTasks(JSONObject task, String oldExecutorId, String newExecutorId, List<PlusTaskSaveDTO> result) {
        JSONArray children = task.getJSONArray("children");
        if (CollUtil.isNotEmpty(children)) {
            for (int j = 0; j < children.size(); j++) {
                JSONObject child = children.getJSONObject(j);
                // 处理当前子任务
                dealCurrentPlanExecutor(child, oldExecutorId, newExecutorId, result);
                // 递归处理更深层的子任务
                processChildrenTasks(child, oldExecutorId, newExecutorId, result);
            }
        }
    }

    private void dealCurrentPlanExecutor(JSONObject task, String oldExecutorId, String newExecutorId, List<PlusTaskSaveDTO> result) {
        String executorOID = task.getString("executorOID");
        if (StringUtils.isNotEmpty(executorOID) && executorOID.equals(oldExecutorId)) {
            PlusTaskSaveDTO taskJavaObject = task.toJavaObject(PlusTaskSaveDTO.class);
            taskJavaObject.setExecutorOID(newExecutorId);
            result.add(taskJavaObject);
        }
    }

    private void getNeedReplaceJobList(List<TyppmJobVO> result, String oldExecutorId,
                                       List<TyppmJobVO> needReplaceJobList) {
        if (CollUtil.isNotEmpty(result)) {
            for (TyppmJobVO jobVO : result) {
                if (oldExecutorId.equals(jobVO.getExecutorOID()) && !"已完成".equalsIgnoreCase(jobVO.getState())) {
                    needReplaceJobList.add(jobVO);
                }
                List<TyppmJobVO> children = jobVO.getChildren();
                getNeedReplaceJobList(children, oldExecutorId, needReplaceJobList);
            }
        }
    }



}